import sys,os,re
from time import sleep
from datetime import datetime
#windows窗口程序
from PyQt5 import QtCore, QtGui, QtWidgets
#ssh连接程序
from SshConnect import SshConnectTest

#输入内容判断
def input_judge(hostip,username,password,cluster_cidr,service_cluster_ip_range):
    if not hostip:
        return "主机地址为空"
    if not username:
        return "主机账号为空"
    if not password:
        return "主机密码为空"
    if not cluster_cidr:
        return "集群地址为空"
    if not service_cluster_ip_range:
        return "服务地址为空"

    #IPv4正则表达式
    regular_ipv4 = '(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}'
    check_result = re.search(regular_ipv4, hostip, re.I)
    if check_result == None:
        return "输入的主机地址格式不正确"
    #ipv6的正则表达式
    regular_ipv6 = '((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))'
    #校验输入的IPv6地址是否正确
    check_result1 = re.search(regular_ipv6, cluster_cidr, re.I)
    if check_result1 == None:
        return "输入的集群地址格式不正确"
    #校验输入的IPv6地址是否正确
    check_result2 = re.search(regular_ipv6, service_cluster_ip_range, re.I)
    if check_result2 == None:
        return "输入的服务地址格式不正确"

    ssh = SshConnectTest(host = hostip, user = username, password = password)
    if ssh.errorstr:
        return "无法登陆主机，请检查IP地址及账号密码"
    ssh.clear()
    
    return "输入内容检查无误"

#主窗口程序
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1434, 790)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        #Master节点地址-标题
        self.label_1 = QtWidgets.QLabel(self.centralwidget)
        self.label_1.setGeometry(QtCore.QRect(10, 10, 110, 26))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_1.setFont(font)
        self.label_1.setObjectName("label_1")
        #Master节点地址-内容框体
        self.E_IP = QtWidgets.QLineEdit(self.centralwidget)
        self.E_IP.setGeometry(QtCore.QRect(120, 10, 200, 30))
        font = QtGui.QFont()
        font.setFamily("Agency FB")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.E_IP.setFont(font)
        self.E_IP.setObjectName("E_IP")
        #Master节点账号-标题
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(10, 55, 110, 26))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_2.setFont(font)
        self.label_2.setObjectName("label_2")
        # Master节点账号-内容框体
        self.E_User = QtWidgets.QLineEdit(self.centralwidget)
        self.E_User.setGeometry(QtCore.QRect(120, 55, 200, 30))
        font = QtGui.QFont()
        font.setFamily("Agency FB")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.E_User.setFont(font)
        self.E_User.setObjectName("E_User")
        #Master节点密码-标题
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(10, 100, 110, 31))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_3.setFont(font)
        self.label_3.setObjectName("label_3")
        # Master节点密码-内容框体
        self.E_Passwd = QtWidgets.QLineEdit(self.centralwidget)
        self.E_Passwd.setGeometry(QtCore.QRect(120, 100, 200, 30))
        font = QtGui.QFont()
        font.setFamily("Agency FB")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.E_Passwd.setFont(font)
        self.E_Passwd.setObjectName("E_Passwd")
        #cluster_cidr地址-标题
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(10, 145, 110, 31))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_4.setFont(font)
        self.label_4.setObjectName("label_4")
        #cluster_cidr地址-内容框体
        self.cluster_cidr = QtWidgets.QLineEdit(self.centralwidget)
        self.cluster_cidr.setGeometry(QtCore.QRect(120, 145, 200, 30))
        font = QtGui.QFont()
        font.setFamily("Agency FB")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.cluster_cidr.setFont(font)
        self.cluster_cidr.setObjectName("cluster_cidr")
        #service_cluster_ip_range地址-标题
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setGeometry(QtCore.QRect(10, 190, 110, 31))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_5.setFont(font)
        self.label_5.setObjectName("label_5")
        #service_cluster_ip_range地址-内容框体
        self.service_cluster_ip_range = QtWidgets.QLineEdit(self.centralwidget)
        self.service_cluster_ip_range.setGeometry(QtCore.QRect(120, 190, 200, 30))
        font = QtGui.QFont()
        font.setFamily("Agency FB")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.service_cluster_ip_range.setFont(font)
        self.service_cluster_ip_range.setObjectName("service_cluster_ip_range")
        #执行按钮
        self.B_Connect = QtWidgets.QPushButton(self.centralwidget)
        self.B_Connect.setGeometry(QtCore.QRect(60, 245, 141, 41))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.B_Connect.setFont(font)
        self.B_Connect.setObjectName("B_Connect")

        #右侧框体
        self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(350, 0, 1121, 781))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.textEdit = QtWidgets.QTextEdit(self.verticalLayoutWidget)
        self.textEdit.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.textEdit.setLineWidth(0)
        self.textEdit.setObjectName("textEdit")
        self.verticalLayout_3.addWidget(self.textEdit)

        #将对应标题转换为汉字
        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        #设置执行按钮功能
        self.B_Connect.clicked.connect(MainWindow.connectServer_click)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "基于K8S+Calico的IPv6自动化部署工具"))
        self.label_1.setText(_translate("MainWindow", "主机地址:"))
        self.label_2.setText(_translate("MainWindow", "主机账号:"))
        self.label_3.setText(_translate("MainWindow", "主机密码:"))
        self.label_4.setText(_translate("MainWindow", "集群地址:"))
        self.label_5.setText(_translate("MainWindow", "服务地址:"))
        self.B_Connect.setText(_translate("MainWindow", "执行操作"))

class query_window(QtWidgets.QMainWindow):
    client=None
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        
    #Excute 的 点击动作绑定一个事件处理函数
    def connectServer_click(self):
        #获取前端填入数据
        hostip = self.ui.E_IP.text()
        username = self.ui.E_User.text()
        password = self.ui.E_Passwd.text()
        cluster_cidr = self.ui.cluster_cidr.text()
        service_cluster_ip_range = self.ui.service_cluster_ip_range.text()

        # hostip = "192.168.12.23"
        # username = "root"
        # password = "CK8no54dmbyc"
        # #定义集群地址
        # cluster_cidr = "2409:8c20:1831:0503:01ff:fffe:1070:0000/108"
        # #定义服务地址
        # service_cluster_ip_range = "2409:8c20:1831:0503:01ff:fffe:1080:0000/108"

        #创建日志文件目录,判断目录是否存在，如果不存在，则新建目录
        logpath = os.path.expanduser('~\Documents')+"\kube-ipv6-capacity"
        if not os.path.exists(logpath):
            os.mkdir(logpath, 777)
        #打开日志文件
        logfile = open(logpath+'/'+datetime.now().strftime('%Y_%m_%d')+'.txt','a',encoding='utf-8')
        #对前端输入进行判断
        input_result = input_judge(hostip,username,password,cluster_cidr,service_cluster_ip_range)
        #将判断结果写入右侧框体中
        self.ui.textEdit.append(input_result+"          "+datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        #将判断结果写入日志中
        logfile.write(input_result+"          "+datetime.now().strftime("%Y-%m-%d %H:%M:%S")+"\n")
        #判断结果正常，开始执行修改程序
        if input_result == "输入内容检查无误":
            ssh = SshConnectTest(host = hostip, user = username, password = password)

            #判断目录是否存在，如果不存在，则新建目录
            logfile.write("创建目录/kube-ipv6-capacity")
            self.ui.textEdit.append("创建目录/kube-ipv6-capacity") 
            ssh.createpath('/kube-ipv6-capacity')

            logfile.write("开始修改apiserver配置！")
            self.ui.textEdit.append("开始修改apiserver配置！")
            #修改apiserver的启动参数
            config_apiserver = []
            #读取文件
            ssh.getfile('/etc/kubernetes/manifests/kube-apiserver.yaml',logpath+"/kube-apiserver.yaml")
            with open(logpath+"/kube-apiserver.yaml","r") as kube_apiserver_read:
                for line in kube_apiserver_read.readlines():
                    if "--service-cluster-ip-range" in line:
                        if ',' in line:#如果行中存在,说明本程序已执行过一次，本次为第二次执行，需删除原有数据
                            line = line.split(',')[0].rstrip()+","+service_cluster_ip_range+"\n"
                        else:
                            #line中自带了回车，必须先清除回车，然后加上字符串后再添加回车
                            line = line.rstrip()+","+service_cluster_ip_range+"\n"
                    config_apiserver.append(line)
            with open(logpath+"/kube-apiserver.yaml",'w') as kube_apiserver_write:
                kube_apiserver_write.write("".join(config_apiserver))
            ssh.putfile(logpath+"/kube-apiserver.yaml", "/etc/kubernetes/manifests/kube-apiserver.yaml")
            logfile.write("apiserver配置修改完成，等待重启！")
            self.ui.textEdit.append("apiserver配置修改完成，等待重启！")
            sleep(60)
            logfile.write("apiserver重启完成！")
            self.ui.textEdit.append("apiserver重启完成！")

            logfile.write("开始修改controller-manager配置！")
            self.ui.textEdit.append("开始修改controller-manager配置！")
            #修改controller-manager的启动参数
            config_controller_manager = []
            ssh.getfile('/etc/kubernetes/manifests/kube-controller-manager.yaml',logpath+"/kube-controller-manager.yaml")
            with open(logpath+"/kube-controller-manager.yaml",'r') as kube_controller_manager_read:
                for line in kube_controller_manager_read.readlines():
                    if "--cluster-cidr" in line:
                        if ',' in line:#如果行中存在,说明本程序已执行过一次，本次为第二次执行，需删除原有数据
                            line = line.split(',')[0].rstrip()+","+cluster_cidr+"\n"
                        else:
                            line = line.rstrip()+","+cluster_cidr+"\n"
                    if "--service-cluster-ip-range" in line:
                        if ',' in line:#如果行中存在,说明本程序已执行过一次，本次为第二次执行，需删除原有数据
                            line = line.split(',')[0].rstrip()+","+service_cluster_ip_range+"\n"
                        else:
                            line = line.rstrip()+","+service_cluster_ip_range+"\n"
                    if "--node-cidr-mask-size-ipv4" in line:#如果行中存在,说明本程序已执行过一次，本次为第二次执行，此处仅需跳过
                        pass
                    elif "--node-cidr-mask-size-ipv6" in line:#如果行中存在,说明本程序已执行过一次，本次为第二次执行，此处仅需跳过
                        pass
                    elif "--node-cidr-mask-size" in line:
                        line = line.replace("=","-ipv4=")+"    - --node-cidr-mask-size-ipv6=118\n" 
                    config_controller_manager.append(line)
            with open(logpath+"/kube-controller-manager.yaml",'w') as kube_controller_manager_write:
                kube_controller_manager_write.write("".join(config_controller_manager))
            ssh.putfile(logpath+"/kube-controller-manager.yaml", '/etc/kubernetes/manifests/kube-controller-manager.yaml')
            logfile.write("controller-manager配置修改完成，等待重启！")
            self.ui.textEdit.append("controller-manager配置修改完成，等待重启！")
            sleep(10)
            logfile.write("controller-manager重启完成！")
            self.ui.textEdit.append("controller-manager重启完成！")

            logfile.write("开始修改kube-proxy配置！")
            self.ui.textEdit.append("开始修改kube-proxy配置！")
            #修改kube-proxy的配置
            ssh.excute('kubectl get cm -n kube-system kube-proxy -oyaml > /kube-ipv6-capacity/kube-proxy.yaml')
            sleep(1)
            config_kube_proxy = []
            ssh.getfile("/kube-ipv6-capacity/kube-proxy.yaml",logpath+"/kube-proxy.yaml")
            with open(logpath+"/kube-proxy.yaml",'r') as kube_proxy_read:
                for line in kube_proxy_read.readlines():
                    if "clusterCIDR:" in line:
                        if ',' in line:#如果行中存在,说明本程序已执行过一次，本次为第二次执行，需删除原有数据
                            line = line.split(',')[0].rstrip()+","+cluster_cidr+"\n"
                        else:
                            line = line.rstrip()+","+cluster_cidr+"\n"
                    config_kube_proxy.append(line)
            with open(logpath+"/kube-proxy.yaml",'w') as kube_proxy_write:
                kube_proxy_write.write("".join(config_kube_proxy))
            ssh.putfile(logpath+"/kube-proxy.yaml", '/kube-ipv6-capacity/kube-proxy.yaml')
            #更新configmap文件
            ssh.excute('kubectl delete cm -n kube-system kube-proxy')
            ssh.excute('kubectl apply -f /kube-ipv6-capacity/kube-proxy.yaml')
            logfile.write("cm kube-proxy配置修改完成！")
            self.ui.textEdit.append("cm kube-proxy配置修改完成！")
            #重启kube-proxy
            ssh.excute('kubectl rollout restart -n kube-system ds kube-proxy')
            logfile.write("ds kube-proxy重启完成！")
            self.ui.textEdit.append("ds kube-proxy重启完成！")

            logfile.write("开始修改calico-config配置！")
            self.ui.textEdit.append("开始修改calico-config配置！")
            #修改calico配置
            ssh.excute('kubectl get cm -n kube-system calico-config -oyaml > /kube-ipv6-capacity/calico-config.yaml')
            sleep(1)
            config_calico = []
            ssh.getfile("/kube-ipv6-capacity/calico-config.yaml",logpath+"/calico-config.yaml")
            with open(logpath+"/calico-config.yaml",'r') as calico_read:
                for line in calico_read.readlines():
                    if '"type": "calico-ipam"' in line:
                        if '"type": "calico-ipam",' in line:
                            pass
                        else:
                            line = line.rstrip()+',\n              "assign_ipv4": "true",\n              "assign_ipv6": "true"\n'
                    config_calico.append(line)
            with open(logpath+"/calico-config.yaml",'w') as calico_write:
                calico_write.write("".join(config_calico))
            ssh.putfile(logpath+"/calico-config.yaml", '/kube-ipv6-capacity/calico-config.yaml')
            #更新configmap文件
            ssh.excute('kubectl delete cm -n kube-system calico-config')
            ssh.excute('kubectl apply -f /kube-ipv6-capacity/calico-config.yaml')
            logfile.write("cm calico-config配置修改完成！")
            self.ui.textEdit.append("cm calico-config配置修改完成！")

            logfile.write("开始修改calico-node配置！")
            self.ui.textEdit.append("开始修改calico-node配置！")
            #修改calico-node环境变量
            ssh.excute('kubectl get ds -n kube-system calico-node -oyaml > /kube-ipv6-capacity/calico-node.yaml')
            sleep(1)
            config_calico_node = []
            delete_flag = False #需要删除- name: FELIX_IPV6SUPPORT后一行value: "False"
            first_excute = True #首先遍历整个文件，判断是否是初次执行
            ssh.getfile("/kube-ipv6-capacity/calico-node.yaml",logpath+"/calico-node.yaml")
            with open(logpath+"/calico-node.yaml",'r') as calico_node_read:
                first_excute = True
                for line in calico_node_read.readlines():
                    if "CALICO_IPV6POOL_BLOCK_SIZE" in line:
                        first_excute = False
                        break
            with open(logpath+"/calico-node.yaml",'r') as calico_node_read:
                for line in calico_node_read.readlines():
                    if not first_excute:#如果不是初次执行，只需要更换cluster_cidr地址
                        if '- name: CALICO_IPV6POOL_CIDR' in line:
                            line = line.rstrip()+'\n          value: '+cluster_cidr+'\n'
                            delete_flag = True
                            config_calico_node.append(line)
                            continue #截断本次循环，执行下一次循环
                        if delete_flag:
                            delete_flag = False
                            continue
                    else:
                        if '- name: FELIX_IPV6SUPPORT' in line:
                            line = line.rstrip()+'\n          value: "true"\n'
                            line = line+'        - name: IP6\n          value: autodetect\n'
                            line = line+'        - name: CALICO_IPV6POOL_CIDR\n          value: '+cluster_cidr+'\n'
                            line = line+'        - name: CALICO_IPV6POOL_BLOCK_SIZE\n          value: "118"\n'
                            line = line+'        - name: CALICO_IPV6POOL_NAT_OUTGOING\n          value: "true"\n'
                            delete_flag = True
                            config_calico_node.append(line)
                            continue #截断本次循环，执行下一次循环
                        if delete_flag:
                            delete_flag = False
                            continue
                    config_calico_node.append(line)
            with open(logpath+"/calico-node.yaml",'w') as calico_node_write:
                calico_node_write.write("".join(config_calico_node))
            ssh.putfile(logpath+"/calico-node.yaml", '/kube-ipv6-capacity/calico-node.yaml')
            logfile.write("ds calico-node配置修改完成！")
            self.ui.textEdit.append("ds calico-node配置修改完成！")
            #重启calico-node
            ssh.excute('kubectl delete ds -n kube-system calico-node','r')
            ssh.excute('kubectl apply -f /kube-ipv6-capacity/calico-node.yaml','r')
            logfile.write("ds calico-node重启完成！")
            self.ui.textEdit.append("ds calico-node重启完成！")

            logfile.write("运行已完成，请测试业务！")
            self.ui.textEdit.append("运行已完成，请测试业务！")
            ssh.clear()
        logfile.close()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = query_window()
    window.show()
    sys.exit(app.exec_())